package genericity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 定义:任何的泛型变量（比如这里的T）都是派生自Object,所以我们在填充泛型变量时，
 * 只能使用派生自Object的类，比如String,Integer,Double等
 * 而不能使用原始的变量类型，比如int,double,float等
 */
public class TClass<T> {
    public TClass() {
    }

    private T x;  //定义变量
    private T y;

    public TClass(T x, T y) {
        this.x = x;
        this.y = y;
    }

    public T getX() { //作为返回值
        return x;
    }

    public void setX(T x) { //作为参数
        this.x = x;
    }

    public T getY() {
        return y;
    }

    public void setY(T y) {
        this.y = y;
    }
}

/**
 * 多泛型变量定义
 */
class InfoDemo<T, U> {
    private T x;
    private T y;
    private U name;
    //就不生成set,get方法了,指定就行了
    /**
     * E — Element，常用在java Collection里，如：List<E>,Iterator<E>,Set<E>
     * K,V — Key，Value，代表Map的键值对
     * N — Number，数字
     * T — Type，类型，如String，Integer等等
     */


}

/**
 * 泛型接口
 */
interface Info1<T> {        // 在接口上定义泛型
    public T getVar(); // 定义抽象方法，抽象方法的返回值就是泛型类型

    public void setVar(T x);
}

/**
 * 非泛型类继承
 */
class InfoImpl implements Info1<String> {   // 定义泛型接口的子类
    private String var;                // 定义属性

    public InfoImpl(String var) {        // 通过构造方法设置属性内容
        this.setVar(var);
    }

    @Override
    public void setVar(String var) {
        this.var = var;
    }

    @Override
    public String getVar() {
        return this.var;
    }
}

/**
 * 泛型类继承
 */
class InfoImpl1<T> implements Info1<T> {   // 定义泛型接口的子类
    private T var;             // 定义属性

    public InfoImpl1(T var) {     // 通过构造方法设置属性内容
        this.setVar(var);
    }

    public void setVar(T var) {
        this.var = var;
    }

    public T getVar() {
        return this.var;
    }
}

/**
 * 多个泛型变量的类继承
 */
class InfoImpl2<T, K, U> implements Info1<U> {   // 定义泛型接口的子类
    private U var;
    private T x;
    private K y;

    public InfoImpl2(U var) {        // 通过构造方法设置属性内容
        this.setVar(var);
    }

    public void setVar(U var) {
        this.var = var;
    }

    public U getVar() {
        return this.var;
    }
}

/**
 * 泛型函数定义
 */
class StaticFans {
    //静态函数
    public static <T> void staticMethod(T a) {
        System.out.println("StaticMethod: " + a.toString());
    }

    //普通函数
    public <T> void OtherMethod(T a) {
        System.out.println("OtherMethod: " + a.toString());
    }

    //返回值中存在泛型
    public static <T> List<T> parseArray(String response, Class<T> object) {
//        List<T> modelList = JSON.parseArray(response, object); //没有JSON库 会报错;
        List<T> modelList=new ArrayList<>();
        return modelList;
    }

    //定义泛型数组
    public static <T> T[] fun1(T... arg) {  // 接收可变参数
        return arg;            // 返回泛型数组
    }

    /**
     * 定义受限泛型 设置上限      (这块忘了的话可以看看,GenericClass1.java里的实例,那个简单清晰点)
     * <p>
     * <T extends BoundingType>  此定义表示T应该是BoundingType的子类型（subtype）。
     * 设置泛型的上限范围 如:extends Number 所有number子类可以
     * <p>
     * extends表示绑定，后面的BindingType即可以是接口，也可以是类
     */
    //绑定接口方法
    public static <T extends Comparable> T min(T... a) {
        T smallest = a[0];
        for (T item : a) {
            if (smallest.compareTo(item)) {
                smallest = item;
            }
        }
        return smallest;
    }

    //绑定类方法
    public static <T extends Fruit> String getFruitName(T t) {
        return t.getName();
    }

}

interface Comparable<T> {
    boolean compareTo(T i);
}


class StringCompare implements Comparable<StringCompare> {
    public String mStr;

    public StringCompare(String string) {
        this.mStr = string;
    }

    @Override
    public boolean compareTo(StringCompare str) {
        if (mStr.length() > str.mStr.length()) {
            return true;
        }
        return false;
    }
}

class Fruit {
    public String name;


    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}


class Banana extends Fruit {
    public Banana() {
        setName("bababa");
    }
}

class Apple extends Fruit {
    public Apple() {
        setName("apple");
    }
}

/**
 * 通配符？的extends绑定
 * <p>
 * 定义受限泛型 设置上限      (这块忘了的话可以看看,GenericClass1.java里的实例,那个简单清晰点)
 * <T extends BoundingType>  此定义表示T应该是BoundingType的子类型（subtype）。
 * 设置泛型的上限范围 如:extends Number 所有number子类可以
 */

class PointExtra<T extends Number> {
    private T x;       // 表示X坐标
    private T y;       // 表示Y坐标

    public PointExtra() {

    }

    public PointExtra(T x, T y) {
        this.x = x;
        this.y = y;
    }

    public void setX(T x) {
        this.x = x;
    }

    public void setY(T y) {
        this.y = y;
    }

    public T getX() {
        return this.x;
    }

    public T getY() {
        return this.y;
    }
}

/**
 * 通配符？的super绑定
 */
class CEO extends Manager {
}

class Manager extends Employee {
}

class Employee {
}


class GenericsDemo24 {
    public static void main(String[] args) {
        //非泛型类继承
        InfoImpl i = new InfoImpl("HAHA");
        System.out.println(i.getVar());

        //泛型类继承
//        InfoImpl1<String> i1=new InfoImpl1<String>("123");
//        System.out.println(i1.getVar());

        //多个泛型变量的类继承
//        InfoImpl2<Integer, Double, String> i2 = new InfoImpl2<Integer, Double, String>("harvic");
//        System.out.println(i2.getVar());

        //静态方法
        StaticFans.staticMethod("haha");  //使用方法一
        StaticFans.<String>staticMethod("haha");  //使用方法二,推荐

        //常规方法
        StaticFans staticFans = new StaticFans();
        staticFans.OtherMethod(123);//使用方法一
        staticFans.<Integer>OtherMethod(123);//使用方法二,推荐

        //使用泛型数组
        Integer[] in = StaticFans.fun1(1, 2, 3, 4, 5, 6);
        System.out.println(Arrays.toString(in));
        Integer[] result = StaticFans.fun1(in);
        System.out.println(Arrays.toString(result));

        // extends实例：绑定接口
        StringCompare sresult = StaticFans.min(new StringCompare("123"), new StringCompare("234"), new StringCompare("59897"));
        System.out.println(sresult.mStr);

        // extends实例：绑定类
        String name_1 = StaticFans.getFruitName(new Banana());
        String name_2 = StaticFans.getFruitName(new Apple());
        System.out.println(name_1);
        System.out.println(name_2);

        /**
         * ？与T的区别:   他们俩没有任何联系！！！！！
         * 无边界通配符？则只能用于填充泛型变量T，表示通配任何类型！只是填充方式的一种！！！
         */

        /**
         * 泛型实例,未使用通配符
         */
        TClass<Integer> integerPoint = new TClass<Integer>(3, 3);
        //…………
        TClass<Float> floatPoint = new TClass<Float>(4.3f, 4.3f);
        //…………
        TClass<Double> doublePoint = new TClass<Double>(4.3d, 4.90d);
        //…………
        TClass<Long> longPoint = new TClass<Long>(12l, 23l);
        //…………
        TClass<String> stringPoint = new TClass<String>("12312", "2312");
        /**
         * 无边界通配符 ?
         */
        TClass<?> point;
        point = new TClass<Integer>(3, 3);
        point = new TClass<Float>(4.3f, 4.3f);
        point = new TClass<Double>(4.3d, 4.90d);
        point = new TClass<Long>(12l, 23l);

        /**
         * 通配符？的extends绑定
         * 注意：利用<? extends Number>定义的变量，只可取其中的值，不可修改
         */
        //无边界通配符只是泛型T的填充方式，给他加上限定,临时变量形式
        TClass<? extends Number> pointNum;
            pointNum = new TClass<Number>();
            pointNum = new TClass<Integer>(3, 3);
            pointNum = new TClass<Float>(4.3f, 4.3f);
            pointNum = new TClass<Double>(4.3d, 4.90d);
            pointNum = new TClass<Long>();
            Number y = pointNum.getY();          // 可以取值
//            pointNum.setX(new Integer(123));   // 不可以赋值
//            pointNum = new TClass<String>(); //编译错误
//            pointNum = new TClass<Object>(); //编译错误

        //如果想从根本上解决通配符向上限定问题，需要从pointExtra泛型类定义时加上<T extends Number>:
        PointExtra<?> pointExtra;
            pointExtra = new PointExtra<Float>(4.3f, 4.3f);
            pointExtra = new PointExtra<Number>();
            pointExtra = new PointExtra<Integer>(3, 3);
            pointExtra = new PointExtra<Float>(4.3f, 4.3f);
            pointExtra = new PointExtra<Double>(4.3d, 4.90d);
            pointExtra = new PointExtra<Long>();
//            pointExtra = new PointExtra<String>(); //编译错误
//            pointExtra = new PointExtra<Object>(); //编译错误


        /**
         * 通配符？的super绑定
         *   <? super XXX>则表示填充为任意XXX的父类
         * 定义受限泛型 设置下限
         */
        List<? super Manager> list;
        list = new ArrayList<Employee>(); //工人
        list = new ArrayList<Manager>();  //管理者
//        list = new ArrayList<CEO>();  //因为受限,CEO无法成为引用类型,编译错误

        //存
//        list.add(new Employee()); //编译错误
        list.add(new Manager()); //在传进去list.add()后，会被强制转换为Manager！下同
        list.add(new CEO());
        //取
        Object object = list.get(0);
//        Employee employee = list.get(0);//编译错误


        /**
         * 总结 ? extends 和 the ? super 通配符的特征，我们可以得出以下结论：
         * 如果你想从一个数据类型里获取数据，使用 ? extends 通配符（能取不能存）
         * 如果你想把对象写入一个数据结构里，使用 ? super 通配符（能存不能取）
         * 如果你既想存，又想取，那就别用通配符。
         */

    }

}